#include<iostream>
#include<algorithm>

// 1.1 swap
template<class T>
void swap(T& a, T& b)
{
    T temp = a; a = b; b = temp;
}

// 1.2 count
template<class T>
int count(const T arr[], int size, const T& value)
// int count(const T* arr, int size, T value)
/* int count(const T& arr, int size, typename T::value_type value)
C++ 规定，任何依赖于模板参数的嵌套名称，比如 T::value_type，编译器默认不会知道它是一个类型还是一个静态成员或其他非类型的符号。
因此，编译器要求在这种情况下显式地使用 typename 来告诉它这个名称是一个类型。
没有 typename 的情况下，编译器会假设 T::value_type 是一个非类型成员（比如变量或函数），从而导致编译错误。*/
{
    int count = 0;
    for (int i = 0;i < size;i++) {
        if (arr[i] == value)
            count++;
    }
    return count;
}

// 1.3 fill
template<class T>
void fill(T arr[], int start, int end, const T& value)
{
    for (int i = start;i < end;i++) {
        arr[i] = value;
    }
}

// 1.4 inner_product
template<class T>
T inner_product(const T a[], const T b[], const int& n)
{
    T sum = 0;
    for (int i = 0;i < n;i++) {
        sum += a[i] * b[i];
    }
    return sum;
}

// 1.5 iota : Increment of Time and Arrays
template<class T>
void iota(T arr[], int n, const T& value)
{
    for (int i = 0;i < n;i++) {
        arr[i] = value + i;
    }
}

// 1.6 is_sorted
template<class T>
bool is_sorted(const T arr[], int n)
{
    if (n <= 1) return true;
    T pre = arr[1] - arr[0];
    T cur;
    for (int i = 2;i < n;i++) {
        cur = arr[i] - arr[i - 1];
        if (pre * cur < 0) return false;
        pre = cur;
    }
    return true;
}

// 1.7 mismatch
template<class T>
int mismatch(const T arr[], const T brr[], int n)
{
    for (int i = 0;i < n;i++) {
        if (arr[i] != brr[i]) return i;
    }
    return n;
}

// 1.8 是相同的函数签名，函数签名不包括返回值类型

// 1.10 throw try catch
int abc(int a, int b, int c)
{
    if (a < 0 && b < 0 && c < 0)
        throw 1;
    if (a == 0 && b == 0 && c == 0)
        throw 2;
    return a + b + c;
}

// 1.11 重做1.2
template<class T>
int count2(const T arr[], int n, const T& value)
{
    if (n < 1)
        throw "n must be >=1.";
    int count = 0;
    for (int i = 0;i < n;i++) {
        if (arr[i] == value)
            count++;
    }
    return count;
}

// 1.12 第i行的元素个数为rowSize[i]个
template<class T>
bool make2dArray(T**& x, int numberOfRows, T rowSize[])
{
    x = new T * [numberOfRows];
    for (int i = 0;i < numberOfRows;i++)
        x[i] = new T[rowSize[i]];
    return true;
}

template <class T>
void delete2dArray(T**& x, int numberOfRows)
{
    for (int i = 0;i < numberOfRows;i++)
        delete[] x[i];
    delete[] x;
    x = nullptr;
}

// 1.13  改变一维数组的长度
template<class T>
void changeLength1D(T*& x, int oldLength, int newLength)
{
    if (newLength < 0) throw "new length must be >= 0";
    T* new_x = new T[newLength];
    // int len = std::min(oldLength, newLength);
    // std::copy(x, x + oldLength, new_x);
    int len = newLength < oldLength ? newLength : oldLength;
    for (int i = 0;i < len;i++)
        new_x[i] = x[i];
    delete[] x;
    x = new_x;
}

// 1.14 改变二维数组的行数和列数
template <class T>
void changeLength2D(T**& x, int oldRows, int oldColumnsSize[], int newRows, int newColumnsSize[])
{
    if (oldRows <= 0 || newRows <= 0) throw "rows must be >= 0";
    int* oldMinElement = std::min_element(oldColumnsSize, oldColumnsSize + oldRows);
    int* newMinElement = std::min_element(newColumnsSize, newColumnsSize + newRows);
    if (*oldMinElement <= 0 || *newMinElement <= 0) throw "columns size must be >= 0";

    T** new_x;
    new_x = new T * [newRows];
    for (int i = 0;i < newRows;i++)
        new_x[i] = new T[newColumnsSize[i]];

    for (int i = 0;i < (newRows < oldRows ? newRows : oldRows);i++) {
        int len = newColumnsSize[i] < oldColumnsSize[i] ? newColumnsSize[i] : oldColumnsSize[i];
        for (int j = 0;j < len;j++)
            new_x[i][j] = x[i][j];
    }

    for (int i = 0;i < oldRows;i++)
        delete[] x[i];
    delete[] x;
    x = new_x;
}


int main()
{
    using std::cout;
    using std::endl;
    cout << "-- 1.1 swap --" << endl;
    int a = 1, b = 2;
    cout << "a = " << a << ", b = " << b << endl;
    swap(a, b);
    cout << "a = " << a << ", b = " << b << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.2 count --" << endl;
    int arr[5] = { 1,3,3,4,5 };
    int size = 5;
    int value = 3;
    cout << "count = " << count(arr, size, value) << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.3 fill --" << endl;
    int arr2[5] = { 1,2,3,4,5 };
    for (int i = 0;i < 5;i++) cout << arr2[i] << " ";
    fill(arr2, 2, 5, 0);
    cout << endl;
    for (int i = 0;i < 5;i++) cout << arr2[i] << " ";
    cout << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.4 inner_product --" << endl;
    int a2[5] = { 1,2,3,4,5 };
    int b2[5] = { 1,2,3,4,5 };
    cout << inner_product(a2, b2, 5) << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.5 iota --" << endl;
    int arr3[5];
    for (int i = 0;i < 5;i++) cout << arr3[i] << " ";
    cout << endl;
    iota(arr3, 5, 1);
    for (int i = 0;i < 5;i++) cout << arr3[i] << " ";
    cout << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.6 is_sorted --" << endl;
    int arr4[5] = { 1,2,3,4,5 };
    cout << is_sorted(arr4, 5) << endl;
    int arr5[5] = { 1,2,5,4,3 };
    cout << is_sorted(arr5, 5) << endl;
    int arr6[5] = { 5,4,3,2,1 };
    cout << is_sorted(arr6, 5) << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.7 mismatch --" << endl;
    int arr7[5] = { 1,2,3,4,5 };
    int brr[5] = { 1,2,3,4,5 };
    cout << mismatch(arr7, brr, 5) << endl;
    int arr8[5] = { 1,2,3,4,5 };
    int brr2[5] = { 1,2,3,4,6 };
    cout << mismatch(arr8, brr2, 5) << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.10 throw try catch --" << endl;
    try {
        // cout << abc(-1, -2, -3) << endl;
        cout << abc(0, 0, 0) << endl;
    }
    catch (int e) {
        if (e == 1)
            cout << "error " << e << " : " << "All parameters cannot be less than 0 at the same time." << endl;
        if (e == 2)
            cout << "error " << e << " : " << "All parameters cannot be equal 0 at the same time" << endl;
    }
    cout << "-------------------" << endl;

    cout << "-- 1.11 重做1.2 --" << endl;
    try {
        cout << count2(arr, 0, 3) << endl;
    }
    catch (const char* e) {
        cout << "error : " << e << endl;
    }
    cout << "-------------------" << endl;

    cout << "-- 1.12 第i行的元素个数为rowSize[i]个 --" << endl;
    int** x;
    int rowSize[5] = { 1,2,3,4,5 };
    int res = make2dArray(x, 5, rowSize);
    cout << res << endl;
    for (int i = 0;i < 5;i++)
        for (int j = 0;j < rowSize[i];j++)
            x[i][j] = i * rowSize[i] + j;

    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < rowSize[i];j++)
            cout << x[i][j] << " ";
        cout << endl;
    }
    delete2dArray(x, 5);
    cout << x << endl;
    cout << "-------------------" << endl;

    cout << "-- 1.13  改变一维数组的长度 --" << endl;
    int* arr9 = new int[5];
    for (int i = 0;i < 5;i++) arr9[i] = i;
    for (int i = 0;i < 5;i++) cout << arr9[i] << " ";
    cout << endl;
    changeLength1D(arr9, 5, 10);
    for (int i = 0;i < 10;i++) cout << arr9[i] << " ";
    cout << endl;
    delete[] arr9;
    cout << "-------------------" << endl;

    cout << "-- 1.14 改变二维数组的行数和列数 --" << endl;
    int** x2;
    int oldColumnsSize[5] = { 1,2,3,4,5 };
    int newColumnsSize[5] = { 4,4,4,4,4 };
    make2dArray(x2, 5, oldColumnsSize);
    for (int i = 0;i < 5;i++)
        for (int j = 0;j < oldColumnsSize[i];j++)
            x2[i][j] = i * oldColumnsSize[i] + j;

    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < oldColumnsSize[i];j++)
            cout << x2[i][j] << " ";
        cout << endl;
    }

    changeLength2D(x2, 5, oldColumnsSize, 5, newColumnsSize);
    for (int i = 0;i < 5;i++) {
        for (int j = 0;j < newColumnsSize[i];j++)
            cout << x2[i][j] << " ";
        cout << endl;
    }

    return 0;
}